home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / source / xdme_1.84_src.lha / XDME / Lib / src / Dyn.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-13  |  16.5 KB  |  690 lines

  1. #define REF_VERS 0
  2.  
  3. /******************************************************************************
  4.  
  5.     MODULE
  6.     DYN.c
  7.  
  8.     DESCRIPTION
  9.     Simple Dynamic Strings in "C"
  10.  
  11.     NOTES
  12.       * this file contains 2 implementations:
  13.     one is using bigger base variables (12bytes) and is a little bit faster
  14.     the other is using smaller base variables (4bytes) and is a little bit slower
  15.     (speed is not tested ...)
  16.       * to keep codesize small and for debugging purposes
  17.     (only one function to modify) DynCpy & DynCat are
  18.     using DynIns, so the functions DynCpy and DynCat are
  19.     much slower than necessary.
  20.  
  21.     BUGS
  22.     none known
  23.  
  24.     TODO
  25.     tell me
  26.  
  27.     EXAMPLES
  28.  
  29.     SEE ALSO
  30.  
  31.     HISTORY
  32.     15-09-94 b_noll created
  33.     28-09-94 b_noll enhanced !REF_VERS (REF_VERS is going away)
  34.  
  35. ******************************************************************************/
  36.  
  37.  
  38. /**************************************
  39.           Includes
  40. **************************************/
  41.  
  42. #include <stdlib.h>
  43. #include <stdio.h>
  44. #include <stdarg.h>
  45. #include <string.h>
  46. #include <assert.h>
  47.  
  48. #ifdef AMIGA
  49. #include <clib/exec_protos.h>
  50. extern APTR SysBase;
  51. #include <pragmas/exec_pragmas.h>
  52. #endif
  53.  
  54. //#undef DYNSTR_MACROS
  55. #ifndef   DYN_H
  56. #include "DYN.h"
  57. #endif /* DYN_H */
  58.  
  59. /**************************************
  60.       Internal Defines & Structures
  61. **************************************/
  62.  
  63. #ifndef STREAM
  64. #define STREAM void *
  65. #endif
  66.  
  67. #undef    Prototype
  68. #define Prototype extern
  69.  
  70. #define STRLEN        32       /* each dynamic string is sized ((STRLEN+strlen()-1)/STRLEN)*STRLEN ... */
  71.  
  72. #ifndef TRUE
  73. #define TRUE  1
  74. #define FALSE 0
  75. #define BOOL  int
  76. #endif
  77.  
  78. #define BRA_ do{
  79. #define KET_ }while(0)
  80.  
  81. /**************************************
  82.          Implementation
  83. **************************************/
  84.  
  85. #if REF_VERS /* ******************************************* */
  86.  
  87. struct _DSTR {
  88.     int   Size;
  89.     int   Length;
  90.     char *Str;
  91. }; /* struct _DSTR */
  92. #define DSTR struct _DSTR
  93.  
  94. DSTR _EmptyDyn = {0,0,NULL};
  95.  
  96. void DynInit (DSTR *pstr) {
  97.     *pstr = _EmptyDyn;
  98. } /* DynInit */
  99.  
  100. void DynClear (DSTR *pstr) {
  101.     if (DynValue(pstr))
  102.     free (DynValue(pstr));
  103.     DynInit(pstr);
  104. } /* DynClear */
  105.  
  106. void DynReset (DSTR *pstr) {
  107.     if (DynValue (pstr))
  108.     pstr->Length = strlen(DynValue(pstr));
  109.     else
  110.     pstr->Length = pstr->Size = 0;
  111. } /* DynReset */
  112.  
  113. void DynErase (DSTR *pstr) {
  114.     if (DynValue (pstr))
  115.     *DynValue(pstr) = 0;
  116.     DynReset(pstr);
  117. } /* DynErase */
  118.  
  119. char *DynValue (DSTR *pstr) {
  120.     return pstr->Str;
  121. } /* DynValue */
  122.  
  123. int DynSize (DSTR *pstr) {
  124.     return pstr->Size;
  125. } /* DynSize */
  126.  
  127. int DynLen (DSTR *pstr) {
  128.     return pstr->Length;
  129. } /* DynLen */
  130.  
  131. BOOL  DynCpy    (DSTR *pstr, const char *src) {
  132.     DynClear(pstr);
  133.     DynCat  (pstr, src);
  134. } /* DynCpy */
  135.  
  136. BOOL  DynCat    (DSTR *pstr, const char *src) {
  137.     return DynIns (pstr, src, pstr->Length);
  138. } /* DynCat */
  139.  
  140. BOOL  DynDel    (DSTR *pstr, int pos, int chars) {
  141.     /* ---- Empty? or nothing to Delete */
  142.     if (!pstr->Str || (pstr->Length < pos) || !chars)
  143.     return TRUE;
  144.  
  145.     /* ---- End Truncated? */
  146.     if (pstr->Length < pos + chars) {
  147.     pstr->Length = pos;
  148.     pstr->Str[pos] = 0;
  149.     return TRUE;
  150.     } /* if */
  151.  
  152.     /* ---- Midth Deleted? */
  153.     memcpy (pstr->Str + pos, pstr->Str + pos + chars, pstr->Length + 1 - (chars + pos));
  154.     pstr->Length -= chars;
  155.     return TRUE;
  156. } /* DynDel */
  157.  
  158. BOOL  DynIns    (DSTR *pstr, const char *src, int pos) {
  159.     int   slen, tlen;
  160.     char *inter;
  161.     assert (pstr != NULL);
  162.  
  163.     /* ---- make sure we have consistent data */
  164.     if (!pstr->Str)
  165.     pstr->Length = pstr->Size = 0;
  166.  
  167.     /* ---- Empty append? */
  168.     if (!src)
  169.     return TRUE;
  170.     slen = strlen (src);
  171.     if (!slen)
  172.     return TRUE;
  173.  
  174.     /* ---- Fits into old String? */
  175.     if (slen + pstr->Length < pstr->Size) {
  176.     strins (pstr->Str + pos, src); /* DIFF1_2_Cat */
  177.     pstr->Length += len;
  178.     return TRUE;
  179.     } /* if */
  180.  
  181.     /* ---- New Mem needed */
  182.     if (!(inter = malloc (tlen = (STRLEN * (1 + pstr->Length + slen + STRLEN - 1)/STRLEN ))))
  183.     return FALSE;
  184.  
  185.     strcpy (inter, pstr->Str);
  186.     free   (pstr->Str);
  187.     strins (inter + pos, src); /* DIFF2_2_Cat */
  188.  
  189.     pstr->Length += slen;
  190.     pstr->Size    = tlen;
  191.     pstr->Str  = inter;
  192.     return TRUE;
  193. } /* DynIns */
  194.  
  195.  
  196. #endif /* ************************************************** */
  197.  
  198. /*
  199. #undef DynInit
  200. #undef DynClear
  201. #undef DynDelete
  202. #undef DynReset
  203. #undef DynErase
  204. #undef DynLen
  205. #undef DynSize
  206. #undef DynValue
  207. */
  208.  
  209. #define DB(pstr) (*pstr)
  210.  
  211.  
  212. /* ---- Return the contents of a DSTR */
  213. #ifndef DynValue
  214. Prototype char *DynValue (DSTR *pstr);
  215. char *DynValue (DSTR *pstr) {
  216.     assert (pstr != NULL);
  217.     if (DB(pstr))
  218.     return DB(pstr)->Str;
  219.     return "";
  220. } /* DynValue */
  221. #define DynValue(pstr)  ((*(pstr))? ((*(pstr))->Str): "")
  222. #endif
  223.  
  224.  
  225. /* ---- Return the sizeof() of a DSTR */
  226. #ifndef DynSize
  227. Prototype int DynSize (DSTR *pstr);
  228. int DynSize (DSTR *pstr) {
  229.     assert (pstr != NULL);
  230.     if (DB(pstr))
  231.     return DB(pstr)->Size;
  232.     return 0;
  233. } /* DynSize */
  234. #define DynSize(pstr)   ((*(pstr))? ((*(pstr))->Size): 0)
  235. #endif
  236.  
  237.  
  238. /* ---- Return the strlen() of a DSTR */
  239. #ifndef DynLen
  240. Prototype int DynLen (DSTR *pstr);
  241. int DynLen (DSTR *pstr) {
  242.     assert (pstr != NULL);
  243.     if (DB(pstr))
  244.     return DB(pstr)->Length;
  245.     return 0;
  246. } /* DynLen */
  247. #define DynLen(pstr)    ((*(pstr))? ((*(pstr))->Length): 0)
  248. #endif
  249.  
  250.  
  251. /* ---- Initialize a DSTR */
  252. #ifndef DynInit
  253. Prototype void DynInit (DSTR *pstr);
  254. void DynInit (DSTR *pstr) {
  255.     assert (pstr != NULL);
  256.     *pstr = EmptyDyn;
  257. } /* DynInit */
  258. #define DynInit(pstr)   *(pstr) = EmptyDyn
  259. #endif
  260.  
  261.  
  262. /* ---- Reset a DSR to initialisation-state */
  263. #ifndef DynClear
  264. Prototype void DynClear (DSTR *pstr);
  265. void DynClear (DSTR *pstr) {
  266.     assert (pstr != NULL);
  267.     if (DB(pstr))
  268.     free (DB(pstr));
  269.     DynInit(pstr);
  270. } /* DynClear */
  271. #define DynClear(pstr)  BRA_ DSTR d; if ((d = *(pstr))) free(d); *(pstr) = EmptyDyn; KET_
  272. #endif
  273.  
  274.  
  275. /* ---- Delete a DSTR - make in uninitlialized */
  276. #ifndef DynDelete
  277. Prototype void DynDelete (DSTR *pstr);
  278. void DynDelete (DSTR *pstr) {
  279.     assert (pstr != NULL);
  280.     DynClear (pstr);
  281. } /* DynDelete */
  282. #define DynDelete(pstr) DynClear(pstr)
  283. #endif
  284.  
  285.  
  286. /* ---- Make sure a DSTR is consistent */
  287. #ifndef DynReset
  288. Prototype void DynReset (DSTR *pstr);
  289. void DynReset (DSTR *pstr) {
  290.     assert (pstr != NULL);
  291.     if (DB(pstr))
  292.     DB(pstr)->Length = strlen (DB(pstr)->Str);
  293. } /* DynReset */
  294. #define DynReset(pstr)  BRA_ DSTR d; if ((d = *(pstr))) d->Length = strlen(d->Str);     KET_
  295. #endif
  296.  
  297.  
  298. /* ---- Set the contents of a DSTR to "" and keep the DSTR consistent */
  299. #ifndef DynErase
  300. Prototype void DynErase (DSTR *pstr);
  301. void DynErase (DSTR *pstr) {
  302.     assert (pstr != NULL);
  303.     if (DB(pstr))
  304.     DB(pstr)->Length = DB(pstr)->Str[0] = 0;
  305. } /* DynErase */
  306. #define DynErase(pstr)  BRA_ DSTR d; if ((d = *(pstr))) d->Length = d->Str[0] = 0;      KET_
  307. #endif
  308.  
  309.  
  310. /* ---- Delete text inside a DSTR */
  311. Prototype BOOL DynDel     (DSTR *pstr, int pos, int chars);
  312. BOOL DynDel    (DSTR *pstr, int pos, int chars) {
  313.     struct _DSTR *dstr;
  314.  
  315.     assert (pstr != NULL);
  316.     dstr = DB(pstr);
  317.     /* ---- Empty? or nothing to Delete */
  318.     if (!(dstr = DB(pstr)) || (dstr->Length < pos) || !chars)
  319.     return TRUE;
  320.  
  321.     /* ---- End Truncated? */
  322.     if (dstr->Length < pos + chars) {
  323.     dstr->Length = pos;
  324.     dstr->Str[pos] = 0;
  325.     return TRUE;
  326.     } /* if */
  327.  
  328.     /* ---- Midth Deleted? */
  329.     memcpy (dstr->Str + pos, dstr->Str + pos + chars, dstr->Length + 1 - (chars + pos));
  330.     dstr->Length -= chars;
  331.     return TRUE;
  332. } /* DynDel */
  333.  
  334.  
  335. /* ---- Make sure a DSTR is at least big enough to keep a certain amount of memory */
  336. Prototype BOOL    DynExpand (DSTR *pstr, int max);
  337. BOOL  DynExpand (DSTR *pstr, int max) {
  338.     DSTR new;
  339.     assert (pstr != NULL);
  340.  
  341.     /* ---- no more heap needed? */
  342.     if (DB(pstr) && (DynSize(pstr) > max))
  343.     return TRUE;
  344.  
  345.     /* ---- make size block aligned */
  346.     max = STRLEN * ((max + STRLEN - 1) / STRLEN);
  347.  
  348.     /* ---- New Mem needed */
  349.     if (!(new = malloc (sizeof (*new) + max)))
  350.     return FALSE;
  351.  
  352.     /* ---- init the new str */
  353.     new->Size     = max;
  354.     new->Length    = 0;
  355.     new->Str[0] = 0;
  356.  
  357.     /* ---- get the old string's data and release it */
  358.     if (DB(pstr)) {
  359.     new->Length = DB(pstr)->Length;
  360.     strcpy (new->Str, DB(pstr)->Str);
  361.     free   (DB(pstr));
  362.     } /* if */
  363.     *pstr = new;
  364.  
  365.     return TRUE;
  366. } /* DynExpand */
  367.  
  368.  
  369. /* ---- Insert text of a certain length into a DSTR */
  370. static BOOL _DynLIns (DSTR *pstr, const char *src, int pos, int slen) {
  371.     int   use, len;
  372.     struct _DSTR *dstr;
  373.     assert (pstr != NULL);
  374.  
  375.     /* ---- Empty append? */
  376.     if (!src)
  377.     return TRUE;
  378.  
  379.     /* ---- make sure we have at least partly consistent data */
  380.     if (!(dstr = DB(pstr)))
  381.     use = len = 0;
  382.     else {
  383.     use = dstr->Length;
  384.     len = dstr->Size;
  385.     } /* if */
  386.  
  387.     /* ---- what shall happen, if pos>use? */
  388.     /* if (pos > use) return FALSE; */
  389.     if (pos > use) pos = use;
  390.  
  391.     slen = strlen (src);
  392.     /* ---- isn't it better o make sure *pstr!=NULL - remove the next line! */
  393.     /* if (!slen) return TRUE; */
  394.  
  395.     /* ---- Fits into old String?      */
  396.     /*        New Mem needed and got it? */
  397.     if ((slen + use >= len) && !DynExpand (pstr, use + slen))
  398.     return FALSE;
  399.     dstr = DB(pstr);
  400.  
  401.     /* strins (dstr->Str + pos, src); /* this is the only DIFF_2_Cat */
  402.     memmove(dstr->Str + pos + slen, dstr->Str + pos, dstr->Length + 1 - pos);
  403.     memmove(dstr->Str + pos, src, slen);
  404.     dstr->Length  += slen;
  405.  
  406.     return TRUE;
  407. } /* _DynLIns */
  408.  
  409.  
  410. /* ---- Insert text into a DSTR */
  411. Prototype BOOL    DynIns      (DSTR *pstr, const char *src, int pos);
  412. BOOL  DynIns    (DSTR *pstr, const char *src, int pos) {
  413.     assert (pstr != NULL);
  414.     return _DynLIns (pstr, src, pos, src? strlen (src): 0);
  415. } /* DynIns */
  416.  
  417.  
  418. /* ---- Append text to a DSTR */
  419. Prototype BOOL DynCat     (DSTR *pstr, const char *src);
  420. BOOL DynCat    (DSTR *pstr, const char *src) {
  421.     // return _DynLIns (pstr, src, DynLen(pstr), src? strlen (src): 0);
  422.     int slen;
  423.     assert (pstr != NULL);
  424.     if (src && DynExpand(pstr, slen = strlen(src) + DynLen(pstr))) {
  425.     strcat (DynValue(pstr) + DynLen(pstr), src);
  426.     DB(pstr)->Length = slen;
  427.     return TRUE;
  428.     } /* if */
  429.     return FALSE;
  430. } /* DynCat */
  431.  
  432.  
  433. /* ---- Replace the contents of a DSTR */
  434. Prototype BOOL DynCpy     (DSTR *pstr, const char *src);
  435. BOOL DynCpy    (DSTR *pstr, const char *src) {
  436.     assert (pstr != NULL);
  437.     DynErase (pstr);
  438.     return DynCat (pstr, src);
  439. } /* DynCpy */
  440.  
  441.  
  442. /* The DynD* functions are a little bit faster when copying data between
  443. ** 2 DSTRs that the way via DynValue and the normal Dyn* functions */
  444.  
  445.  
  446. /* ---- Insert text into a DSTR from a DSTR */
  447. Prototype BOOL    DynDIns    (DSTR *pstr, DSTR *src, int pos);
  448. BOOL  DynDIns     (DSTR *pstr, DSTR *src, int pos) {
  449.     assert (pstr != NULL);
  450.     return _DynLIns (pstr, DynValue(src), pos, DynLen(src));
  451. } /* DynDIns */
  452.  
  453.  
  454. /* ---- Append text to a DSTR from a DSTR */
  455. Prototype BOOL DynDCat      (DSTR *pstr, DSTR *src);
  456. BOOL DynDCat    (DSTR *pstr, DSTR *src) {
  457.     assert (pstr != NULL);
  458.     return _DynLIns (pstr, DynValue(src), DynLen(pstr), DynLen(src));
  459. } /* DynDCat */
  460.  
  461.  
  462. /* ---- Replace the contents of a DSTR from a DSTR */
  463. Prototype BOOL DynDCpy      (DSTR *pstr, DSTR *src);
  464. BOOL DynDCpy    (DSTR *pstr, DSTR *src) {
  465.     assert (pstr != NULL);
  466.     DynErase (pstr);
  467.     return DynDCat (pstr, src);
  468. } /* DynDCpy */
  469.  
  470.  
  471. /* ---- _TRY_ to replace the value of a STR */
  472. /*    the use of this function is recommended, if the  */
  473. /*    old value of a DSTR shall stay valid in the case */
  474. /*    there is not enough heap to hold the new value     */
  475. /*    the price for this security, is less speed     */
  476. Prototype BOOL DynSCpy (DSTR *pstr, const char *src);
  477. BOOL DynSCpy (DSTR *pstr, const char *src) {
  478.     int slen;
  479.     assert (pstr != NULL);
  480.     if (DynExpand(pstr, slen = strlen(src))) {
  481.     strcpy (DynValue(pstr), src);
  482.     DB(pstr)->Length = slen;
  483.     return TRUE;
  484.     } /* if */
  485.     return FALSE;
  486. } /* DynSCpy */
  487.  
  488.  
  489. Prototype BOOL DynDSCpy (DSTR *pstr, DSTR *src);
  490. BOOL DynDSCpy (DSTR *pstr, DSTR *src) {
  491.     int slen;
  492.     assert (pstr != NULL);
  493.     if (DynExpand(pstr, slen = DynLen(src))) {
  494.     strcpy (DynValue(pstr), DynValue(src));
  495.     DB(pstr)->Length = slen;
  496.     return TRUE;
  497.     } /* if */
  498.     return FALSE;
  499. } /* DynDSCpy */
  500.  
  501.  
  502. /* ---- Replace some chars within a DSTR */
  503. Prototype BOOL DynReplace (DSTR *pstr, const char *src, int pos, int chars);
  504. BOOL DynReplace (DSTR *pstr, const char *src, int pos, int chars) {
  505.     int slen;
  506.     slen = src? strlen(src): 0;
  507.     assert (pstr != NULL);
  508.  
  509.     /* ---- we cannot write behind the end */
  510.     if (pos > DynLen(pstr))
  511.     return FALSE;
  512.  
  513.     /* ---- adjust the removed chars */
  514.     if (pos + chars > DynLen(pstr))
  515.     chars = DynLen(pstr) - pos;
  516.  
  517.     /* ---- expand the string */
  518.     if (DynExpand(pstr, DynLen(pstr) + slen - chars)) {
  519.  
  520.     /* ---- make room for the replace part */
  521.     if (slen != chars);
  522.         memmove(DynValue(pstr) + pos + slen, DynValue(pstr) + pos + chars, 1 + DynLen(pstr) - (pos + chars));
  523.  
  524.     /* ---- insert the replace part */
  525.     memmove(DynValue(pstr) + pos, src, slen);
  526.     DB(pstr)->Length += slen - chars;
  527.     return TRUE;
  528.     } /* if */
  529.     return FALSE;
  530. } /* DynReplace */
  531.  
  532.  
  533. /* ---- read all incoming data from a stream and insert it into a DSTR */
  534. Prototype BOOL DynGIns (DSTR *pstr, int pos, STREAM instream, char *(read)(STREAM));
  535. BOOL DynGIns (DSTR *pstr, int pos, STREAM instream, char *(read)(STREAM)) {
  536.     char *data;
  537.     assert (pstr != NULL);
  538.  
  539.     /* ---- I do not think that function needs any explanation */
  540.     while (data = (*read)(instream)) {
  541.     int olen = DynLen(pstr);
  542.  
  543.     if (!DynIns(pstr, data, pos))
  544.         return FALSE;
  545.  
  546.     pos += DynLen(pstr) - olen;
  547.     } /* while */
  548.  
  549.     return TRUE;
  550. } /* DynGIns */
  551.  
  552.  
  553. /* ---- Append several strings at one time ... */
  554. Prototype BOOL vDynAppend (DSTR *pstr, int num, va_list adds);
  555. BOOL vDynAppend (DSTR *pstr, int num, va_list adds) {
  556.     int   il;
  557.     char* istr;
  558.     assert (pstr != NULL);
  559.  
  560.     /* ---- append all adds to pstr */
  561.     while (num-- > 0) {
  562.     istr = va_arg(adds, char*);
  563.  
  564.     /* ---- ignore empty strings */
  565.     if (!istr)
  566.         continue;
  567.  
  568.     /* ---- make sure we have enough mem */
  569.     il = strlen (istr);
  570.  
  571.     if (DynExpand(pstr, il + DynLen(pstr)))
  572.         return FALSE;
  573.  
  574.     /* ---- append the string */
  575.     strcpy (DynValue(pstr) + DynLen(pstr), istr);
  576.     DB(pstr)->Length += il;
  577.     } /* while */
  578.  
  579.     return TRUE;
  580. } /* vDynAppend */
  581.  
  582.  
  583. /* ---- Append a single char to a DSTR        */
  584. /*    Not the fastest way, but it should work */
  585. Prototype int DynPutc (DSTR *pstr, int c);
  586. int DynPutc (DSTR *pstr, int c) {
  587.     unsigned char bf[2] = { 0, '\0' };
  588.  
  589.     bf[0] = c & 255;
  590.     return DynCat(pstr, bf);
  591. } /* DynPutc */
  592.  
  593.  
  594. #ifdef AMIGA
  595.  
  596. #if defined(__SASC)
  597. #define PREFIX __asm
  598. #define __D0(x) register __d0 x
  599. #define __A3(x) register __a3 x
  600. #elif defined(_DCC)
  601. #define PREFIX
  602. #define __D0(x)  __D0 x
  603. #define __A3(x)  __A3 x
  604. #endif
  605.  
  606. /* ---- Not the fastest way, but it should work */
  607. static PREFIX int _DynPutc (__A3( DSTR *pstr ), __D0( int c )) {
  608.     unsigned char bf[2] = { 0, '\0' };
  609.  
  610.     bf[0] = c & 255;
  611.     return DynCat(pstr, bf);
  612. } /* DynPutc */
  613.  
  614. /* ---- That function is _NOT_PORTABLE_! nor it can test, */
  615. /*    if the operation ended successfully.          */
  616. /*    btw. remember - we have Flexprintf ;-)          */
  617. Prototype BOOL vDynPrintf (DSTR *pstr, const char *tplt, va_list args);
  618. BOOL vDynPrintf (DSTR *pstr, const char *tplt, va_list args) {
  619.     assert (pstr != NULL);
  620.     RawDoFmt ((void *)tplt, args, (void *)_DynPutc, pstr);
  621.     return TRUE;
  622. } /* vDynPrintf */
  623.  
  624. #else
  625.  
  626. /* no amiga? poor guy... */
  627. /* ---- Keep on Dreamin'  8-)  ...  btw. we have Flexprintf ;-) */
  628. /*    Since there is no standardized way to access the format */
  629. /*    function used by the *printf-funcs, and since I don't   */
  630. /*    want to reinvent the wheel, so.else may write that func */
  631. /* BOOL vDynPrintf (DSTR *pstr, const char *tplt, va_list args) {
  632. } /* vDynPrintf */
  633.  
  634. #endif
  635.  
  636. /* ---- strip all ending spaces */
  637. Prototype BOOL DynStripES (DSTR *pstr);
  638. BOOL DynStripES (DSTR *pstr) {
  639.     int   i;
  640.     char *str;
  641.     assert (pstr != NULL);
  642.  
  643.     /* ---- init */
  644.     if (!(i = DynLen(pstr)))
  645.     return FALSE;
  646.     str = DynValue(pstr);
  647.     --i;
  648.  
  649.     /* ---- remove all ending spaces */
  650.     while ((i >= 0) && (str[i] < 33))
  651.     str[i--] = 0;
  652.  
  653.     /* ---- restore the consistency */
  654.     if (i < 0) {
  655.     DynClear(pstr);
  656.     return TRUE;
  657.     } else if (DynLen(pstr) > i + 1) {
  658.     DB(pstr)->Length = i + 1;
  659.     return TRUE;
  660.     } else
  661.     return FALSE;
  662. } /* DynStripES */
  663.  
  664. Prototype BOOL DynGetFile (DSTR *pstr, const char *name);
  665. BOOL DynGetFile (DSTR *pstr, const char *name) {
  666.     FILE *fi;
  667.     if ((fi = fopen (name, "r"))) {
  668.     int size;
  669.     fseek(fi, 0, SEEK_END);
  670.     if (!DynExpand(pstr, 1 + (size = ftell(fi)))) {
  671.         fclose (fi);
  672.         return FALSE;
  673.     } /* if */
  674.     fseek(fi, 0, SEEK_SET);
  675.  
  676.     fread (DynValue(pstr), 1, size, fi);
  677.     DynValue(pstr)[size] = 0;
  678.  
  679.     fclose(fi);
  680.     return TRUE;
  681.     } /* if */
  682.     return FALSE;
  683. } /* DynGetFile */
  684.  
  685.  
  686. /******************************************************************************
  687. *****  END DYN.c
  688. ******************************************************************************/
  689.  
  690.